    ;
    ; STOCK 810 ROM
    ;
    ; Automata states.
    ; Each bit has a different
    ; meaning and is used to
    ; know what should be done
    ; next.
    ;
    AUT01    = $01
    AUT02    = $02
    AUTWAIT  = $04
    AUTVER   = $08
    AUT10    = $10
    AUT20    = $20
    AUT40    = $40
    AUT80    = $80
    ;
    ; Command Status bits.
    ; Used in LSTATCMD.
    ;
    STATNONE = $00
    STATCMD  = $01
    STATDATA = $02
    STATERR  = $04
    STATWP   = $08
    STATACT  = $10
    ;
    ; Controller Status bits.
    ; Used in LSTATHW.
    ;
    CTRLBUSY = $01
    CTRLDRQ  = $02
    CTRLLOST = $04
    CTRLCRC  = $08
    CTRLRNF  = $10
    CTRLTYPE = $20
    CTRLWP   = $40
    CTRLMON  = $80
    ;
    ; Controller commands.
    ; These values are written
    ; into WCOMMAND register
    ; to ask the controller
    ; for a particular task.
    ;
    WCMDWTRK = $F4
    WCMDFINT = $D0
    WCMDWSEC = $A8
    WCMDRSEC = $88
    WCMDSEEK = $13
    WCMDREST = $00
    ;
    ; Inverted controller
    ; commands.
    ; Commands are written
    ; inverted int the
    ; controller regsiters.
    ;
    IWCWTRK  = $FF-WCMDWTRK
    IWCFINT  = $FF-WCMDFINT
    IWCWSEC  = $FF-WCMDWSEC
    IWCRSEC  = $FF-WCMDRSEC
    IWCSEEK  = $FF-WCMDSEEK
    IWCREST  = $FF-WCMDREST
    ;
    ; Length of Status answer
    ; Length of checksum
    ; Timeout for command
    ;
    STATLEN  = $04
    SUMLEN   = $01
    TIMEOUT  = $E0
    ;
    ; Answer to a command.
    ;
    ACK      = $41 ; 'A'
    COMPLETE = $43 ; 'C'
    ERROR    = $45 ; 'E'
    NACK     = $4E ; 'N'
    ;
    ; WDC 1771 registers
    ;
    WSTATUS  = $00 ; Read
    WCOMMAND = $00 ; Write
    WTRACK   = $01
    WSECTOR  = $02
    WDATA    = $03
    ;
    ; WDC base address
    ;
    BASEWDC  = $0000
    ;
    ; WDC addresses
    ;
    WDCSTAT  = BASEWDC+WSTATUS
    WDCCOMND = BASEWDC+WCOMMAND
    WDCTRACK = BASEWDC+WTRACK
    WDCSECT  = BASEWDC+WSECTOR
    WDCDATA  = BASEWDC+WDATA
    ;
    ; RIOT 6532 registers
    ;
    DRA      = $00
    DDRA     = $01
    DRB      = $02
    DDRB     = $03
    EDGECTRL = $04
    WR1NOIT  = $14
    WR8NOIT  = $15
    WR1IT    = $1C
    WR64IT   = $1E
    WR1024IT = $1F
    ;
    ; Port A bits
    ;
    SWITCH1  = $01
    DRVMOTOR = $02
    SWITCH2  = $04
    UNUSED   = $08
    WPT1771  = $10
    VSS6532  = $20
    IRQ1771  = $40
    DRQ1771  = $80
    ;
    ; Port B bits
    ;
    DATAOUT  = $01
    VCCRDY   = $02
    PHASE4   = $04
    PHASE3   = $08
    PHASE2   = $10
    PHASE1   = $20
    COMMAND  = $40
    DATAIN   = $80
    ;
    ; RIOT base address
    ;
    BASERIOT = $0380
    ;
    ; RIOT addresses
    ;
    RIOTDRA  = BASERIOT+DRA
    RIOTDDRA = BASERIOT+DDRA
    RIOTDRB  = BASERIOT+DRB
    RIOTDDRB = BASERIOT+DDRB
    RIOTEDGE = BASERIOT+EDGECTRL
    RIOTW1NO = BASERIOT+WR1NOIT
    RIOTW8NO = BASERIOT+WR8NOIT
    RIOTW1   = BASERIOT+WR1IT
    RIOTW64  = BASERIOT+WR64IT
    RIOTW1K  = BASERIOT+WR1024IT
    ;
    ; Sector buffer
    ;
    SECTOR   = $0080
    ;
    ; Code equates
    ;
    L00E0    = $00E0
    L00E1    = $00E1
    L00E2    = $00E2
    L00E3    = $00E3
    L00F8    = $00F8
    ;
    L0180    = $0180
    LCMDDRV  = $0181
    LCMDCMD  = $0182
    LCMDAUX1 = $0183
    LCMDAUX2 = $0184
    LSNDBYTE = $0186
    L0187    = $0187
    LCURDRB  = $01CD
    LCURTRK  = $01CE
    L01CF    = $01CF
    LSTATCMD = $01D0
    LSTATHW  = $01D1
    LSTATTIM = $01D2
    LUNUSED  = $01D3
    LSTATSUM = $01D4
    LSAVAUX2 = $01D7
    LSAVAUX1 = $01D8
    LTRKNUM  = $01DA
    LSECNUM  = $01DB
    LAUTOM   = $01DD
    LENDCMD  = $01DE
    LPAUSE   = $01DF
    L01E0    = $01E0
    L01E1    = $01E1
    L01E2    = $01E2
    L01E3    = $01E3
    L01E4    = $01E4
    LJMPCMD  = $01E8
    LOFSCMD  = $01EA
    L01EB    = $01EB
    ;
    ; Start of code
    ;
             *= $0800
    ;
    ; Code starts here when
    ; the drive is turned on.
    ;
    START    CLD
    ;
    ; Configure DRVMOTOR and
    ; UNUSED pins as output.
    ; All other pins (SWITCH1,
    ; SWITCH2, WPT1771,...)
    ; are input pins.
    ;
             LDA #DRVMOTOR+UNUSED
             STA RIOTDRA
             STA RIOTDDRA
    ;
    ; Configure PHASE1-4 pins
    ; as output. All other pins
    ; are input pins even
    ; DATAOUT so that no data is
    ; sent on the SIO bus now.
    ;
             LDX #PHASE1+PHASE2+PHASE3+PHASE4
             STX RIOTDDRB
             STX RIOTEDGE
             LDX #0
             STX RIOTDRB
    ;
    ; Stop current controller
    ; operation (if any) by
    ; sending a Force Interrupt
    ; command. This will fill
    ; the status register.
    ;
             LDA #IWCFINT
             STA WDCCOMND
    ;
    ; Remember to wait so that
    ; Force Interrupt command
    ; is not cancelled.
    ;
             LDA #AUTWAIT+AUT01
             STA LAUTOM
    ;
    ; Fill last part of status
    ; buffer returned on a
    ; GET STATUS command.
    ;
             LDA #TIMEOUT
             STA LSTATTIM
             LDA #0
             STA LUNUSED
    ;
    ; Sleep to let Force
    ; Interrupt command
    ; terminate.
    ;
             JSR LCHKWAIT
             LDY #$27
             JSR L0C8B
             STY WDCTRACK
             DEY
             STY WDCSECT
             JSR LCLRSTAT
             JSR LCHKPRT
             LDX #$01
             STX L01EB
    ;
    ; Reset stack.
    ; Get ready for the next
    ; command from the computer.
    ;
    LRESSTK  LDX #$FF
             TXS
             LDA #$D8
             JSR L0C1B
             STY L01CF
    ;
    ; Restore head to track 0.
    ;
    L084C    LDA #IWCREST
             STA WDCCOMND
             LDA #AUT20
    ;
    ; Jump over sector table
    ;
             JMP LOVERTBL
    ;
    ; Maybe unused...
    ; Who knows ?
    ;
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0
    ;
    ; 18 sector numbers
    ;
    LFMTTAB  .BYTE $00,$FE,$FC,$FA
             .BYTE $F8,$F6,$F4,$F2
             .BYTE $F0,$EE,$FD,$FB
             .BYTE $F9,$F7,$F5,$F3
             .BYTE $F1,$EF
    ;
    LOVERTBL JSR LORAUT
    L0883    BIT RIOTDRA
             BVS L088E
             JSR L0CAB
             JMP L0883
    L088E    DEC L01EB
             BPL L084C
    L0893    LDX #$80
             LDY L01CF
             BEQ L08AA
             JSR L08ED
             STY L01CF
             JSR L0CAB
    L08A3    LDA RIOTW8NO
             BPL L08A3
             BMI L0893
    L08AA    LDA #UNUSED
             STA RIOTDRA
             LDA #0
             STA RIOTDRB
             LDA #$DF
             JSR LANDAUT
             LDA #AUTWAIT
             JSR LORAUT
             JMP L0CAB
    ;
    ; Check if sector number
    ; in DAUX1/DAUX2 is valid
    ; ($1 to $2D0).
    ;
    LCHKSEC  LDX LCMDAUX2
             LDA LCMDAUX1
             BEQ LSECLOW
    ;
    ; Check high limit.
    ;
    LSECHIGH CPX #$03
             BCS LSECERR
             CMP #$D1
             BCS LSECLAST
    ;
    ; Sector number is valid
    ;
    LSECOK   CLC
             RTS
    ;
    ; Check low limit.
    ;
    LSECLOW  CPX #0
             BNE LSECHIGH
    ;
    ; Sector number is out of
    ; range.
    ;
    LSECERR  SEC
             RTS
    ;
    ; If DAUX1 is higher than
    ; $D0 then DAUX2 should not
    ; exceed $1.
    ;
    LSECLAST CPX #$02
             BEQ LSECERR
             JMP LSECOK
             RTS
    ;
    ; Sleep for a certain amount
    ; of time.
    ;
    LSLEEP   STA LPAUSE
    LWAIT    DEY
             BNE LWAIT
             DEC LPAUSE
             BNE LWAIT
             RTS
    L08ED    LDA #$29
             STA RIOTW64
             LDA RIOTDRB
             AND #PHASE1+PHASE2+PHASE3+PHASE4
             INX
             BMI L090C
             INC LCURTRK
             LSR A
             STA LCURDRB
             AND #$02
             BEQ L091E
             LDA #$20
             ORA LCURDRB
             BPL L0921
    L090C    DEC LCURTRK
             ASL A
             STA LCURDRB
             AND #$40
             BEQ L091E
             LDA #$04
             ORA LCURDRB
             BPL L0921
    L091E    LDA LCURDRB
    L0921    STA RIOTDRB
             DEY
             RTS
    ;
    ; GET SECTOR
    ; ----------
    ;
    LGET     JSR LCHKSEC
             BCS LBADSEC
    ;
    ; Wait for SIO COMMAND to
    ; be clear and send ACK to
    ; the computer.
    ;
             JSR LCMDACK
             JSR LMOTORON
             JSR LCHKWAIT
             JSR LSEEKTRK
    L0937    LDA #IWCRSEC
             STA WDCCOMND
    L093B    BVS L094C
             LDA RIOTW1
    L0940    BIT RIOTDRA
             BPL L093B
             LDA WDCDATA
             INX
             STA SECTOR,X
             BPL L0940
    L094C    JSR L0970
             BCS L0965
    L0951    LDA #COMPLETE
    L0953    STA LSNDBYTE
             JSR LCHKDATA
             STA L0187
             JSR LDATAOUT
             JSR L0E0F
             JMP LRESSTK
    L0965    BNE L0937
    L0967    LDA #ERROR
             JMP L0953
    LBADSEC  JMP LBADCMD
             .BYTE $AD
    L0970    LDA WDCSTAT
             STA LSTATHW
             EOR #$FF
             BNE L0984
             CLC
             LDA #$FB
             JSR LANDSTAT
    L097F    JSR L0F68
             DEY
             RTS
    L0984    CPY #$02
             BNE L09A3
             AND #CTRLRNF
             BEQ L09A3
             STY LPAUSE
             JSR LCHKWAIT
             LDY #$2B
             JSR L0C8B
             LDA LTRKNUM
             JSR L0C1B
             JSR L0F18
             LDY LPAUSE
    L09A3    LDA #STATERR
             JSR LORSTAT
             SEC
             JMP L097F
    ;
    ; FORMAT
    ; ------
    ;
    LFORMAT  JSR LCMDACK
             JSR LMOTORON
             JSR LCHKWAIT
             LDY #$2B
             JSR L0C8B
             JSR L0F63
             LDA RIOTDRA
             AND #WPT1771
             BEQ LNWPROT
             LDA #STATWP
             JSR LORSTAT
             JMP L0A95
    LNWPROT  LDA #$FF
             STA L00E3
             JSR L09EB
    L09D3    DEC L00E3
             LDA L00E3
             CMP #$D7
             BEQ L09E3
             LDX #$80
             JSR L09E8
             JMP L09D3
    L09E3    JMP L0AA3
             BCS L09E8
    L09E8    JSR L0B6D
    L09EB    LDA #LFMTTAB&$FF
             STA L00E0
             LDA #LFMTTAB/256
             STA L00E1
             LDA RIOTW1NO
             LDA #$ED
             STA L00E2
             LDY #$FF
             LDX #$FF
             LDA #IWCWTRK
             STA WDCCOMND
             JSR L0A8D
             LDA #$0D
             STA RIOTW1K
             LDY #$FF
             JSR L0A80
             STX RIOTW1K
             LDY #$03
             JSR L0A8D
             LDY #$0B
             JSR L0A80
    L0A1C    LDY #$06
             JSR L0A80
             LDY #$01
             JSR L0A8D
             LDY L00E3
             JSR L0A8D
             LDY #$FF
             JSR L0A8D
             LDY L00E2
             JSR L0A8D
             LDY #$FF
             JSR L0A8D
             LDY #$08
             JSR L0A8D
             LDY #$11
             JSR L0A80
             LDY #$04
             JSR L0A8D
             LDY #$80
             LDX #0
             JSR L0A80
             LDY #$08
             JSR L0A8D
             LDY #$09
             LDX #$FF
             JSR L0A80
             JSR L0A8D
             INC L00E0
             BMI L0A79
             JSR L0A8D
             LDA (L00E1,X)
             STA L00E2
             JMP L0A6F
    L0A6D    BVS L0A95
    L0A6F    BIT RIOTDRA
             BPL L0A6D
             STY WDCDATA
             JMP L0A1C
    L0A79    LDA #IWCFINT
             STA WDCCOMND
             RTS
    L0A7E    BVS L0A95
    L0A80    BIT RIOTDRA
             BPL L0A7E
             STX WDCDATA
             DEY
             BNE L0A80
             RTS
    L0A8B    BVS L0A95
    L0A8D    BIT RIOTDRA
             BPL L0A8B
             STY WDCDATA
             RTS
    L0A95    LDX #$FF
             STX SECTOR
             STX SECTOR+1
             LDA WDCSTAT
             STA LSTATHW
             JMP L0E71
    L0AA3    LDX #0
             STX L01E1
    L0AA8    LDA LCURTRK
             STA WDCTRACK
             LDA #$FE
    L0AAF    STA LSECNUM
             STA WDCSECT
             LDY #$02
             STY L01E0
    L0AB9    JSR L0F81
             LDY #$01
             JSR L0970
             BCS L0AF3
    L0AC3    LDA LSECNUM
             SEC
             SBC #$04
             CMP #$EA
             BNE L0ACF
             LDA #$FB
    L0ACF    CMP #$EB
             BNE L0AD5
             LDA #$FC
    L0AD5    CMP #$EC
             BNE L0ADB
             LDA #$FD
    L0ADB    CMP #$E9
             BNE L0AAF
             LDA LCURTRK
             CMP #$FF
             BEQ L0AF0
             LDX #0
             LDY #$01
             JSR L0F18
             JMP L0AA8
    L0AF0    JMP L0E58
    L0AF3    DEC L01E0
             BNE L0AB9
             LDX L01E1
             JMP L0E79
    ;
    ; Get DRVMOTOR bit from
    ; Port A.
    ;
    LDRVBIT  LDA RIOTDRA
             LSR A
             LSR A
    ;
    ; Set the STATACT bit
    ; (active drive) in the
    ; command status byte
    ; if the DRVMOTOR bit
    ; is set.
    ;
             LDA #STATACT
             BCS LORSTAT
             LDA #STATNONE
    ;
    ; modify command status
    ; byte.
    ;
    LORSTAT  ORA LSTATCMD
             STA LSTATCMD
             RTS
    ;
    ; Set command status byte
    ; by clearing it and ORing
    ; it with the Accumulator.
    ;
    LSETSTAT PHA
             LDA #0
             AND LSTATCMD
             STA LSTATCMD
             PLA
             JMP LORSTAT
             RTS
    LORAUT   ORA LAUTOM
             STA LAUTOM
             RTS
    LANDAUT  AND LAUTOM
             STA LAUTOM
             RTS
    ;
    ; Clear all status bits
    ; except Write Protect flag.
    ;
    LCLRSTAT LDA #STATWP
    ;
    ; Clear some status bits.
    ;
    LANDSTAT AND LSTATCMD
             STA LSTATCMD
             RTS
    L0B35    LDA RIOTDRB
             BPL L0B35
             TXA
             BEQ L0B67
             LDA L0180,X
             EOR #$FF
             STA L0180,X
    L0B45    NOP
             NOP
             NOP
             LDY #$78
    L0B4A    NOP
             NOP
             NOP
             NOP
             LDA RIOTDRB
             ROL A
             ROR LCMDDRV,X
             INY
             BPL L0B4A
             INX
             CPX LENDCMD
             BNE L0B35
             LDA L0180,X
             EOR #$FF
             STA L0180,X
             RTS
    L0B67    NOP
             NOP
             NOP
             JMP L0B45
    L0B6D    LDA #$02
             JSR LSLEEP
             JSR L08ED
             RTS
    ;
    ; Receive a sector (128 bytes)
    ; from computer. The byte is
    ; transmitted bit after bit
    ; through the DATAIN line of
    ; port B.
    ;
    LRCVSEC  LDX #0
             LDY #$07
             STY LENDCMD
    ;
    ; Wait for the start bit.
    ;
    LWSTART  LDA RIOTDRB
             BPL LWSTART
    ;
    ; Do not invert byte in the
    ; first iteration because we
    ; did not read any byte yet.
    ;
             TXA
             BEQ LRFIRST
    ;
    ; Invert all bits of the byte
    ; that has been received.
    ;
             LDA SECTOR-1,X
             EOR #$FF
             STA SECTOR-1,X
    ;
    ; Loop to receive all bytes.
    ;
    LRCVBYTE NOP
             NOP
             NOP
             LDY #$78
    ;
    ; Loop to receive all bits of
    ; a byte.
    ;
    LRCVBIT  NOP
             NOP
             NOP
             LDA SECTOR
    ;
    ; Get DATAIN line of port B
    ; and save it into SECTOR
    ; buffer.
    ;
             LDA RIOTDRB
             ROL A
             ROR SECTOR,X
    ;
    ; Next bit...
    ;
             INY
             BPL LRCVBIT
    ;
    ; Next byte...
    ;
             INX
             BPL LRCVNEXT
    ;
    ; All bytes have been received.
    ;
             LDX #$06
             JSR L0B35
             LDA L00F8,X
             EOR #$FF
             STA L00F8,X
             RTS
    ;
    ; One NOP for timing and get
    ; ready for next byte.
    ;
    LRCVNEXT NOP
             JMP LWSTART
    ;
    ; Spend time to wait for the
    ; end of the start bit
    ; transmission.
    ;
    LRFIRST  NOP
             NOP
             NOP
             JMP LRCVBYTE
    ;
    ; Compute a checksum of a
    ; command.
    ; Upon entry,
    ; - X contains the offset
    ;   of the command from the
    ;   label LCMDDRV.
    ; - Address LENDCMD contains
    ;   the last offset of the
    ;   command from the label
    ;   LCMDDRV.
    ; This subroutine returns
    ; the checksum in A.
    ;
    LCHKSUM  LDA #0
             CLC
    LCHKLOOP ADC LCMDDRV,X
             PHP
    ;
    ; Is it the last byte of the
    ; command ?
    ;
             INX
             CPX LENDCMD
    ;
    ; Last byte has been
    ; processed. Get out of the
    ; loop.
    ;
             BEQ LCHKEND
             PLP
             JMP LCHKLOOP
    ;
    ; The checksum is computed.
    ; We add the carry.
    ;
    LCHKEND  PLP
             ADC #0
    ;
    ; Compare checksum with the
    ; one from the command. This
    ; is useful only with the
    ; command received from the
    ; computer.
    ;
             CMP LCMDDRV,X
             RTS
    ;
    ; Absolute sector number
    ; given in DAUX1/DAUX2 is
    ; converted into a track
    ; number and a sector number.
    ;
    LCNVSEC  LDA LCMDAUX2
             STA LSAVAUX2
             LDA LCMDAUX1
             STA LSAVAUX1
    ;
    ; Sector number is divided
    ; by 16.
    ;
             LDX #$04
    LCNVDIV  ROR LCMDAUX2
             ROR A
             DEX
             BNE LCNVDIV
             ROR LCMDAUX2
    ;
    ; LCMDAUX2 now contains in
    ; its 4 high bits the value
    ; of DAUX1 4 low bits.
    ; LCMDAUX2 is shifted right
    ; 4 times to have a value
    ; between $01 and $0F.
    ;
             LDX #$04
    LCNVHI   LSR LCMDAUX2
             DEX
             BNE LCNVHI
    ;
    ; A contains absolute
    ; sector number divided
    ; by 16. A is multiplied
    ; by 2 to be compared to
    ; LCMDAUX2.
    ;
    LCNVEND  ASL A
    ;
    ; If C is Clear, it means
    ; that A contains the track
    ; number multiplied by 2.
    ; If C is Set, it means
    ; that LCMDAUX2 should be
    ; adjusted to get the track
    ; number.
    ;
             CMP LCMDAUX2
             BCS LCNVSET
    ;
    ; A is divided by 2 to
    ; get the track number.
    ; It is saved inverted.
    ;
             STA LCMDAUX1
             LSR A
             EOR #$FF
             STA LTRKNUM
             SEC
             LDA LCMDAUX2
             SBC LCMDAUX1
             EOR #$FF
             STA LSECNUM
             RTS
    ;
    ; The division of LCMDAUX2
    ; by 16 has to be adjusted
    ; to get the track number.
    ;
    LCNVSET  LSR A
             TAX
             DEX
             LDA #$10
             CLC
             ADC LCMDAUX2
             STA LCMDAUX2
             TXA
             JMP LCNVEND
    L0C1B    LDX #0
             LDY #0
             SEC
             SBC LCURTRK
             BEQ L0C2F
             BPL L0C2E
             LDX #$80
             EOR #$FF
             CLC
             ADC #$01
    L0C2E    TAY
    L0C2F    RTS
    ;
    ; Check if disk is write
    ; protected and store the
    ; info in status byte.
    ;
    LCHKPRT  LDA RIOTDRA
             AND #WPT1771
             BEQ LNOPRT
             LDA #STATWP
             JSR LORSTAT
             RTS
    LNOPRT   LDA #$F7
             JSR LANDSTAT
             RTS
    ;
    ; Start drive motor (if not
    ; already started).
    ;
    LMOTORON LDA RIOTDRA
    ;
    ; Check DRVMOTOR bit.
    ; If bit is set, it's OK.
    ;
             LSR A
             LSR A
             BCS L0C59
    ;
    ; Start drive motor now.
    ;
             LDA #DRVMOTOR+UNUSED
             STA RIOTDRA
             STA WDCDATA
             LDA #$16
             STA WDCTRACK
             LDA #IWCSEEK
             STA WDCCOMND
    L0C59    LDA #$01
             STA L01EB
             RTS
    L0C5F    LDA LAUTOM
             LSR A
             LSR A
             LSR A
             BCC L0C71
    L0C67    BIT RIOTDRA
             BVC L0C67
             LDA #$FB
             JSR LANDAUT
    L0C71    LDA #STATACT
             JSR LSETSTAT
             RTS
    ;
    ; Wait for the SIO COMMAND
    ; bit to be clear.
    ;
    LCMDACK  BIT RIOTDRB
             BVS LCMDACK
    ;
    ; Send an ACK byte to the
    ; Atari
    ;
    LSENDACK LDA #ACK
    ;
    ; Send a byte from the
    ; Accumulator to the Atari.
    ;
    LSEND    STA LSNDBYTE
             JSR LDATAOUT
             JSR LSNDDATA
             JSR LNODATA
             RTS
    L0C8B    LDX #PHASE1+PHASE4
             STX RIOTDRB
    L0C90    JSR L08ED
             BMI L0C9D
    L0C95    LDA RIOTW8NO
             BPL L0C95
             JMP L0C90
    L0C9D    STY LCURTRK
             TXA
             LDX #$14
    L0CA3    DEY
             BNE L0CA3
             DEX
             BNE L0CA3
             TAX
             RTS
    L0CAB    LDA RIOTDRB
             LSR A
             LSR A
             BCS L0CE4
             LDA LAUTOM
             LSR A
             BCS L0CD7
             BIT RIOTDRB
             BVC L0CCC
             BIT LAUTOM
             BVC L0CEC
             LDA #$29
             JSR LSLEEP
             BIT RIOTDRB
             BVS L0CEC
    L0CCC    LDA LAUTOM
             AND #AUT40+AUT20
             BNE L0CD6
             JMP L0CAB
    L0CD6    RTS
    L0CD7    LDA #$29
             JSR LSLEEP
             LDA #$FE
             JSR LANDAUT
             JMP L0CAB
    L0CE4    LDA #AUT01
             JSR LORAUT
             JMP L0CCC
    L0CEC    LDA #AUT80
             JSR LORAUT
             LDX #0
             LDA #$05
             STA LENDCMD
             JSR L0B35
             LDX #0
             DEC LENDCMD
             JSR LCHKSUM
             BEQ LREADCFG
             LDA #AUT02
             JSR LORAUT
    ;
    ; Get drive number from
    ; the switches at the rear
    ; of the drive. This is
    ; done by reading 2 bits
    ; from Port A of the 6532.
    ; Here are the possible
    ; values:
    ;
    ; SWITCH1 SWITCH2 Drive
    ;   ON      ON      1
    ;   OFF     ON      2
    ;   OFF     OFF     3
    ;   ON      OFF     4
    ;
    ; X will hold the drive
    ; number (by default 4):
    ;
    LREADCFG LDX #$34
    ;
    ; Read port A and keep only
    ; bits from the 2 switches.
    ;
             LDA RIOTDRA
             AND #SWITCH1+SWITCH2
    ;
    ; Switch configuration:
    ; SWITCH1 SWITCH2 Drive
    ;   OFF     OFF     3
    ;
             BEQ LDRV3
    ;
    ; Switch configuration:
    ; SWITCH1 SWITCH2 Drive
    ;   OFF     ON      2
    ;
             CMP #SWITCH2
             BEQ LDRV2
    ;
    ; Switch configuration:
    ; SWITCH1 SWITCH2 Drive
    ;   ON      OFF     4
    ;
             CMP #SWITCH1
             BEQ LDRV4
    ;
    ; Switch configuration:
    ; SWITCH1 SWITCH2 Drive
    ;   ON      ON      1
    ;
             DEX
    LDRV2    DEX
    LDRV3    DEX
    ;
    ; X now holds the drive
    ; number ($31-$34) from the
    ; switches. Check that the
    ; command is for our drive.
    ;
    LDRV4    CPX LCMDDRV
             BEQ LDRVOK
    ;
    ; Command is not for our
    ; drive. Wait for the SIO
    ; COMMAND bit to be clear.
    ;
    LCMDSET1 BIT RIOTDRB
             BVS LCMDSET1
             LDA #$7D
             JSR LANDAUT
             JMP L0CAB
    ;
    ; Check command sent
    ; by computer.
    ;
    LDRVOK   JSR LCHKCMD
             JMP L0CAB
    ;
    ; GET STATUS
    ; ----------
    ;
    LSTATUS  JSR LSENDACK
    ;
    ; Compute checksum on the
    ; status frame answer.
    ;
             LDX #LSTATCMD-LCMDDRV
             LDY #LSTATCMD-LCMDDRV+STATLEN
             STY LENDCMD
             JSR LCHKSUM
    ;
    ; Store checksum at the
    ; end of the status frame
    ; answer.
    ;
             STA LSTATSUM
    ;
    ; Send a COMPLETE code to
    ; the computer.
    ;
             LDA #COMPLETE
             STA LSNDBYTE
             JSR LDATAOUT
    ;
    ; X will hold the count of
    ; bytes to send.
    ; The loop ends when reg X
    ; reaches $80. X is set to
    ; $80 minus the COMPLETE
    ; byte, minus the 4 bytes
    ; of the status answer and
    ; minus the checksum byte.
    ;
             LDX #$80-1-STATLEN-SUMLEN
             JSR LSNDDATA
    ;
    ; Send all status bytes to
    ; the computer.
    ;
    LSTATLP  LDY LSTATCMD-$80+STATLEN+SUMLEN,X
             STY LSNDBYTE
             JSR LSNDDAT2
             BPL LSTATLP
    ;
    ; All bytes have been sent.
    ; Turn off DATA OUT line.
    ;
             JSR LNODATA
    ;
    ; Reset all status bits
    ; except Write Protect then
    ; set Activity bit according
    ; to the WD1771 status.
    ;
             JSR LCLRSTAT
             JSR LDRVBIT
             JMP LRESSTK
    L0D6A    LDY #0
             STY L01E4
             LDA LSECNUM
             EOR #$FF
             STA L01E2
             LDA LCURTRK
             EOR #$FF
             ASL A
             STA L01E3
             ASL A
             ASL A
             ROL L01E4
             ASL A
             ROL L01E4
             ADC L01E3
             TAY
             LDA #0
             ADC L01E4
             JMP L0DDF
    ;
    ; ?
    ;
    LCHKCMD  LDA LAUTOM
             LSR A
             LSR A
             BCS LBADCMD
    ;
    ; The command should be in
    ; the range of $4F to $57.
    ;
             LDA LCMDCMD
             CMP #$4F
             BCC LISFMT
             CMP #$58
             BCS LISFMT
    ;
    ; Command is converted
    ; to a Jump address.
    ; The 3 low bits of the
    ; command byte are
    ; multiplied by 3.
    ; Appearently, $4F is the
    ; same as $57.
    ;
             AND #$07
             STA LOFSCMD
             ASL A
             ADC LOFSCMD
    ;
    ; Then, the result is
    ; added to LTABCMD address.
    ;
             ADC #LTABCMD&$FF
             STA LJMPCMD
             LDA #0
             ADC #LTABCMD/256
             STA LJMPCMD+1
    ;
    ; Execute the routine
    ; corresponding to
    ; the command.
    ;
             JMP (LJMPCMD)
    ;
    ; Is command equal to
    ; $21 (format).
    ;
    LISFMT   CMP #$21
             BEQ LJMPFMT
    ;
    ; The command sent is
    ; unknown !
    ;
    LBADCMD  LDA #STATCMD
             JSR LSETSTAT
             JSR LDRVBIT
    ;
    ; Wait for the SIO COMMAND
    ; bit to be clear.
    ;
    LCMDSET2 BIT RIOTDRB
             BVS LCMDSET2
    ;
    ; Send NACK to the Atari.
    ;
             LDA #NACK
             JSR LSEND
             LDA #$FD
             JSR LANDAUT
             RTS
    ;
    ; Jump to format routine
    ;
    LJMPFMT  JMP LFORMAT
             .BYTE $01
    L0DDF    STA L01E4
             TYA
             CLC
             ADC L01E2
             STA SECTOR,X
             LDA #0
             ADC L01E4
             INX
             STA SECTOR,X
             RTS
    ;
    ; Compute data checksum
    ; and check it.
    ;
    LCHKDATA LDA #0
             TAX
             CLC
    LADDBYTE ADC SECTOR,X
             INX
             BPL LADDBYTE
             ADC #0
             CMP L0187
             RTS
    ;
    ; Set DATAOUT line of port B
    ; as an output line.
    ;
    LDATAOUT LDX RIOTDRB
             STX RIOTDRB
             LDX RIOTDDRB
             INX
             STX RIOTDDRB
             RTS
    L0E0F    LDX #$FF
             JSR LSNDDATA
    L0E14    LDY SECTOR,X
             STY LSNDBYTE
             JSR LSNDDAT2
             BPL L0E14
             LDY L0187
             STY LSNDBYTE
             JSR LSNDDAT2
    ;
    ; Set DATAOUT line of Port B
    ; as an input line: No more
    ; data is sent to the Atari.
    ;
    LNODATA  LDX RIOTDDRB
             DEX
             STX RIOTDDRB
             RTS
    ;
    ; Send a byte to the Atari.
    ; Each bit of the byte is
    ; put on the DATAOUT line of
    ; Port B (LSB bit first).
    ;
    LSNDDATA LDA RIOTDRB
    ;
    ; A start bit (value 0) is
    ; sent before the byte.
    ;
    LSNDDAT2 AND #$FE
             STA RIOTDRB
    ;
    ; Y register will hold the
    ; bit counter (from $78 to
    ; $80).
    ;
             LDY #$78
             BIT SECTOR
    LSNDLOOP BIT SECTOR
             NOP
             NOP
    ;
    ; Send one bit from LSNDBYTE.
    ;
             LSR A
             ROR LSNDBYTE
             ROL A
             STA RIOTDRB
             INY
             BPL LSNDLOOP
    ;
    ; A stop bit (value 1) is
    ; sent after the byte.
    ;
             LSR A
             SEC
             ROL A
             NOP
             NOP
             NOP
             NOP
             NOP
             NOP
             STA RIOTDRB
             INX
             RTS
    L0E58    LDA #$FF
             LDX L01E1
             STA SECTOR,X
             INX
             STA SECTOR,X
             LDA LAUTOM
             AND #AUTVER
             BNE L0E6C
             JMP L0951
    L0E6C    LDA #$F7
             JSR LANDAUT
    L0E71    LDA #STATERR
             JSR LORSTAT
             JMP L0967
    L0E79    LDA #AUTVER
             JSR LORAUT
             JSR L0D6A
             INX
             STX L01E1
             CPX #$7E
             BNE L0E8C
             JMP L0E58
    L0E8C    JMP L0AC3
    ;
    ; This is the jump table
    ; for the drive commands.
    ; The table is the following:
    ;
    ; Command Meaning
    ;   $50   PUT SECTOR
    ;   $51   UNUSED
    ;   $52   GET SECTOR
    ;   $53   GET STATUS
    ;   $54   UNUSED
    ;   $55   UNUSED
    ;   $56   UNUSED
    ; $4F/$57 PUT SECTOR VERIFY
    ;
    LTABCMD  JMP LPUT
             JMP LBADCMD
             JMP LGET
             JMP LSTATUS
             JMP LBADCMD
             JMP LBADCMD
             JMP LBADCMD
             JMP LPUTVER
    ;
    ; Wait for SIO COMMAND to
    ; be clear and send ACK to
    ; computer.
    ;
    LDOPUT   JSR LCMDACK
             JSR LMOTORON
             JSR LRCVSEC
             JSR LCHKDATA
             BNE LBADDATA
             JSR LSENDACK
             JSR LCHKWAIT
             JSR LSEEKTRK
             LDA RIOTDRA
             AND #WPT1771
             BNE LWPROT
    L0EC5    LDA #IWCWSEC
             STA WDCCOMND
    L0EC9    BVS L0EE5
             LDA RIOTW1
             BIT RIOTDRA
             BMI L0EDD
             JMP L0EC9
    L0ED6    BVS L0EE5
    L0ED8    BIT RIOTDRA
             BPL L0ED6
    L0EDD    INX
             LDA SECTOR,X
             STA WDCDATA
             JMP L0ED8
    L0EE5    JSR L0970
             LDA #ERROR
             BCS L0F42
             LDA LAUTOM
             AND #AUTVER
             BEQ L0EFC
             JSR L0F9D
             BCC L0EFC
             LDA #ERROR
             BCS LSENDRES
    L0EFC    LDA #COMPLETE
    L0EFE    JMP LSENDRES
    LBADDATA LDA #STATACT+STATDATA
             JSR LSETSTAT
             LDA #NACK
    LSENDRES JSR LSEND
             JMP LRESSTK
    LWPROT   LDA #STATERR+STATWP
             JSR LORSTAT
             LDA #ERROR
             JMP LSENDRES
    L0F18    BEQ L0F31
    L0F1A    JSR L08ED
             BEQ L0F27
    L0F1F    LDA RIOTW8NO
             BPL L0F1F
             JMP L0F1A
    L0F27    LDA #$50
             STA RIOTW64
    L0F2C    LDA RIOTW8NO
             BPL L0F2C
    L0F31    RTS
    ;
    ; PUT SECTOR with VERIFY
    ; ----------------------
    ;
    LPUTVER  LDA #AUTVER
             JSR LORAUT
    ;
    ; PUT SECTOR
    ; ----------
    ;
    LPUT     JSR LCHKSEC
             BCS L0F3F
             JMP LDOPUT
    L0F3F    JMP LBADCMD
    L0F42    CPY #0
             BEQ L0F49
             JMP L0EC5
    L0F49    BEQ L0EFE
    ;
    ; Convert absolute sector
    ; number to a track and
    ; a sector number then
    ; seek to the track.
    ;
    LSEEKTRK JSR LCNVSEC
             LDA RIOTDRB
             AND #PHASE1+PHASE2+PHASE3+PHASE4
             BNE L0F5A
             LDA #PHASE1+PHASE2
             STA RIOTDRB
    L0F5A    LDA LTRKNUM
             JSR L0C1B
             JSR L0F18
    L0F63    JSR L0C5F
             LDY #$04
    L0F68    LDA #IWCFINT
             STA WDCCOMND
             LDX #$FF
    L0F6E    DEX
             BNE L0F6E
             LDA LTRKNUM
             STA WDCTRACK
             LDA LSECNUM
             STA WDCSECT
             CLV
             DEX
             STX RIOTW1K
             RTS
    L0F81    JSR L0F68
             LDA LCURTRK
             STA WDCTRACK
             LDA #IWCRSEC
             STA WDCCOMND
    L0F8D    BVS L0F9C
             LDA RIOTW1
    L0F92    BIT RIOTDRA
             BPL L0F8D
             LDA WDCDATA
             JMP L0F92
    L0F9C    RTS
    L0F9D    JSR L0F68
             LDY #$01
    L0FA2    INX
             LDA #IWCRSEC
             STA WDCCOMND
    L0FA7    BVS L0FBA
             LDA RIOTW1
    L0FAC    BIT RIOTDRA
             BPL L0FA7
             LDA WDCDATA
             CMP SECTOR,X
             BNE L0FC7
             INX
             BNE L0FAC
    L0FBA    JSR L0970
             BCC L0FC1
             BPL L0FA2
    L0FC1    LDA #$F7
             JSR LANDAUT
             RTS
    L0FC7    JSR L09A3
             JMP L0FC1
    ;
    ; Check the automata to
    ; see if we have to sleep.
    ;
    LCHKWAIT LDA LAUTOM
             AND #AUTWAIT
             BEQ LNOWAIT
             LDA #$50
             JSR LSLEEP
    LNOWAIT  RTS
    ;
    ; This is just a padding so
    ; that the last two WORDs
    ; starts at address $0FFC
    ; and $0FFE.
    ;
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0,0,0,0,0,0,0,0
             .BYTE 0,0
    ;
    ; START is both the IRQ
    ; and RESET address.
    ;
    ; IMPORTANT: if you modify
    ; this source, always check
    ; that this word is at
    ; address $0FFC. If not, add
    ; or remove some of the
    ; padding bytes above.
    ;
             .WORD START ; RESET
             .WORD START ; IRQ
    ;
             .END